# 👉 Intersection Observer 用法详解
# 什么是 Intersection Observer
Intersection Observer 是浏是浏览器提供的一个 异步 API,用来异步检测某个目标元素是否进入或离开了另一个元素(或视口)的可视区域。常用于实现懒加载、元素曝光统计等场景。它的主要优点是:
- 不需要监听滚动事件 + 手动计算位置(节省性能)。
- 异步回调,不会和主线程渲染抢资源。
- 可以设置 阈值,灵活控制触发时机。
在没有 Intersection Observer API 前,如果需要判断一个元素是否进入了视口,一般采用的方法:
监听 scroll 事件,在事件回调中判断元素是否进入了视口。 该方法的原理是监听 scroll 事件,在事件回调中判断元素是否进入了视口,该方法的缺点是会频繁触发 scroll 事件,影响性能。
window.addEventListener('scroll', () => { const scrollBox = document.querySelector('#ad'); const rect = scrollBox.getBoundingClientRect(); if (rect.top < window.innerHeight && rect.bottom >= 0) { // 元素进入了视口 } // 或者获取scroll的位置信息,以下虚拟代码 const scrollTop = scrollBox.scrollTop // box滚动了多少 const containerHeight = scrollBox.clientHeight // box在视口的高度 const scrollHeight = scrollBox.scrollHeight // box的实际高度 if (!this.loading && scrollTop + containerHeight >= scrollHeight - 20) { this.loadMore() } })
使用 getBoundingClientRect() 方法获取元素的位置信息,判断元素是否进入了视口。 该方法返回一个 DOMRect 对象,包含元素的位置信息,如 top、bottom、left、right、width、height 等。该方法的缺点是每次调用都需要计算元素的位置信息,性能受到影响。
const element = document.querySelector('#ad'); const rect = element.getBoundingClientRect(); if (rect.top < window.innerHeight && rect.bottom >= 0) { // 元素进入了视口 }
# 基本用法
const observer = new IntersectionObserver(callback, option);
observer.observe(element);
observer.unobserve(element);
observer.disconnect();
# 参数详解
# callback
callback 回调是 IntersectionObserver 构造函数的第一个参数,当目标元素进入/离开可视区域时触发
回调参数是一个 entries 数组,每一项都是 IntersectionObserverEntry,包含元素的可见性信息。回调函数的参数:
- entries:一个数组,包含所有被观察元素的 IntersectionObserverEntry 对象。
- observer:IntersectionObserver 实例。
IntersectionObserverEntry 对象包含以下属性:
- isIntersecting:元素是否进入了视口。
- intersectionRatio:元素可见比例(0~1)。
- target:被观察的元素。
- time:触发回调的时间。
- boundingClientRect:元素大小和位置。
- intersectionRect:元素可见部分的位置和大小。
- rootBounds:根元素的位置信息,包含 top、bottom、left、right、width、height 等属性。
(entries, observer) => {
entries.forEach(entry => {
console.log(entry.isIntersecting) // 是否进入可视区域
console.log(entry.intersectionRatio) // 可见比例(0~1)
console.log(entry.boundingClientRect) // 元素大小和位置
console.log(entry.intersectionRect) // 可见部分的位置和大小
console.log(entry.target) // 被观察的元素
if (entry.isIntersecting && intersectionRect > 0) {
// 元素进入了视口
}
})
}
# option
const option = {
root: null,
rootMargin: '0px',
threshold: 1.0
}
option 是构造函数的第二个参数,包含以下属性:
- root:用于计算交叉状态的根元素,默认为视口。
- rootMargin:根元素的外边距,类似 CSS 的 margin。
- threshold:触发 callback 的阈值(0~1),表示目标元素可见比例。
# Intersection Observer 工具函数封装
封装一个通用的 Intersection Observer 工具函数,用于监听元素是否进入视口以及处理回调。
function createIntersectionObserver(target, callback, options) {
const observer = new IntersectionObserver(callback, options);
observer.observe(target);
return observer;
}
# 工具函数使用示例
# 元素曝光统计
const observer = createIntersectionObserver(document.querySelector('#ad'), (entry) => {
if (entry.isIntersecting) {
// 统计曝光
console.log('广告曝光:', entry.target.dataset.adid)
// 上报一次即可
observer.unobserve(target);
}
});
# 无限滚动/分页加载
<ul id="list"></ul>
<div id="sentinel"></div>
const loadingDiv = document.querySelector('.sentinel');
createIntersectionObserver(loadingDiv, (entry) => {
if (entry.isIntersecting) {
// 加载数据
loadMoreData();
}
});
# 图片懒加载
createIntersectionObserver(document.querySelector('img[data-src]'), (entry) => {
if (entry.isIntersecting) {
entry.target.src = entry.target.dataset.src;
observer.unobserve(entry.target);
}
});
👉 前端路由实现 →